bitkeeper revision 1.1159.170.104 (4214e770zuNBDS-jq2cWXHSs1B4UOw)
authorsd386@font.cl.cam.ac.uk <sd386@font.cl.cam.ac.uk>
Thu, 17 Feb 2005 18:50:24 +0000 (18:50 +0000)
committersd386@font.cl.cam.ac.uk <sd386@font.cl.cam.ac.uk>
Thu, 17 Feb 2005 18:50:24 +0000 (18:50 +0000)
Extended sedf scheduler (weighted extraqueues), added enhanced scheduling histogramm

xen/common/sched_sedf.c
xen/common/schedule.c
xen/include/xen/sched-if.h

index 10a12b674e0b9cd533fb75371d0e744feb546edf..01e944d5544d14c6988b09ff021203a1e8aca1b8 100644 (file)
 #include <xen/time.h>
 #include <xen/slab.h>
 
+//#include <xen/adv_sched_hist.h>
+
 #define SEDFLEVEL 2
 #define PRINT(_f, _a...)  \
 if ((_f)<=SEDFLEVEL) printk(_a );
 
+//various ways of unblocking domains
+#define UNBLOCK_ISOCHRONOUS_EDF 1
+#define UNBLOCK_EDF 2
+#define UNBLOCK_ATROPOS 3
+#define UNBLOCK_SHORT_RESUME 4
+#define UNBLOCK_BURST 5
+
+#define UNBLOCK UNBLOCK_BURST
+
+//various ways of treating extra-time
+#define EXTRA_OFF 1
+#define EXTRA_ROUNDR 2
+#define EXTRA_SLICE_WEIGHT 3
+#define EXTRA_BLOCK_WEIGHT 4
+
+#define EXTRA EXTRA_OFF
+
+
 /*
        TODO:
        TESTING!
-       implement stylish features!
        tracing instead of PRINTs
 */
 
@@ -29,15 +48,16 @@ if ((_f)<=SEDFLEVEL) printk(_a );
 #define EXTRA_NONE (0)
 #define EXTRA_AWARE (1)
 #define EXTRA_RUNNING (2)
-#define EXTRA_QUANTUM (MICROSECS(1000)) 
+#define EXTRA_QUANTUM (MICROSECS(500)) 
 #define WEIGHT_PERIOD (MILLISECS(100))
 #define WEIGHT_SAFETY (MILLISECS(5))
 
+
 struct sedf_dom_info
 {
        struct domain           *owner;
        struct list_head        list;
-       struct list_head        extralist;
+       struct list_head        extralist[2];
        
        //Parameters for EDF
        s_time_t                period;         //=(relative deadline)
@@ -50,14 +70,17 @@ struct sedf_dom_info
        s_time_t                latency;
        //extra-time status of domain
        short                   extra;
-       //weights for "Scheduling for Beginners/ Lazy/ etc."
+       //weights for "Scheduling for beginners/ lazy/ etc."
        short                   weight;
        
        //Bookkeeping
        s_time_t                absdead;
        s_time_t                sched_start;
        s_time_t                cputime;
-       s_time_t                absblock;
+       s_time_t                absblock;       
+       s_time_t                absunblock;     //time the domain unblocked, used by burst mode to determine unblocking intervals
+       int                     score[2];       //scores for {util, block penalty}-weighted extratime distribution
+       s_time_t                short_block_lost_tot;
        
        //Statistics
        s_time_t                block_time_tot;
@@ -109,6 +132,37 @@ static inline int extraq_on(struct domain *d) {
        return (((EXTRALIST(d))->next != NULL) && (EXTRALIST(d)->next != EXTRALIST(d)));
 }
 
+/* adds a domain to the queue of processes which are aware of extra time. List is sorted by score,
+   where a lower score means higher priority for an extra slice. It also updates the score, by simply subtracting
+   a fixed value from each entry, in order to avoid overflow. The algorithm works by simply charging each domain
+   that recieved extratime with an inverse of its weight.
+ */ 
+static inline void extraq_add_sort_update(struct domain *d, unsigned long sub) {
+       struct list_head     *cur;
+       struct sedf_dom_info *curinf;
+       
+       PRINT(3,"Adding domain %i (score= %llu) to extraq\n",d->id,DOM_INFO(d)->score); 
+       //iterate through all elements to find our "hole" and on our way update all the other scores
+       list_for_each(cur,EXTRAQ(d->processor)){
+               curinf         = list_entry(cur,struct sedf_dom_info,extralist);
+               curinf->score -= sub;
+               if (DOM_INFO(d)->score < curinf->score)
+                       break;
+               else
+                       PRINT(4,"\tbehind domain %i (score= %llu)\n",curinf->owner->id,curinf->score);
+       }
+       //cur now contains the element, before which we'll enqueue
+       PRINT(3,"\tlist_add to %x\n",cur->prev);
+       list_add(EXTRALIST(d),cur->prev);
+       
+       //continue updating the extraq
+       if ((cur != EXTRAQ(d->processor)) && sub) 
+               for (cur = cur->next; cur != EXTRAQ(d->processor); cur = cur-> next) {
+                       curinf         = list_entry(cur,struct sedf_dom_info,extralist);
+                       curinf->score -= sub;
+                       PRINT(4,"\tupdating domain %i (score= %llu)\n",curinf->owner->id,curinf->score);
+               }
+}
 static inline void extraq_check(struct domain *d) {
        if (extraq_on(d)) {
                PRINT(2,"Dom %i is on extraQ\n",d->id);
@@ -120,11 +174,10 @@ static inline void extraq_check(struct domain *d) {
                PRINT(2,"Dom %i is NOT on extraQ\n",d->id);
                if (DOM_INFO(d)->extra != EXTRA_NONE) {
                        PRINT(2,"Added dom %i to extraQ\n",d->id);
-                       extraq_add_tail(d);
+                       extraq_add_sort_update(d, 0);
                }
        }
 }
-
 static inline void __del_from_queue(struct domain *d)
 {
     struct list_head *list = LIST(d);
@@ -277,29 +330,45 @@ static task_slice_t sedf_do_schedule(s_time_t now)
        int                   cpu   = current->processor;
        struct list_head     *runq  = RUNQ(cpu);
        struct list_head     *waitq = WAITQ(cpu);
+       #if (EXTRA > EXTRA_OFF)
        struct list_head     *extraq = EXTRAQ(cpu);
+       #endif
        struct list_head     *cur,*tmp;
        struct sedf_dom_info *curinf;
        task_slice_t          ret;
-
+       #if (EXTRA == EXTRA_SLICE_WEIGHT)
+       unsigned long         oldscore;
+       #endif
        
        //idle tasks don't need any of the following stuf
        if (is_idle_task(inf->owner))
                goto check_waitq;                               //idle task doesn't get scheduled on the runq
-       
+
+       #if (EXTRA > EXTRA_OFF)
        if (unlikely(inf->extra == EXTRA_RUNNING)) {
                //special treatment of domains running in extra time
                inf->extra = EXTRA_AWARE;
                inf->cputime=0;
                inf->extra_time_tot += now - inf->sched_start;
                
-               extraq_del(current);                            //remove extradomain from head of the queue
-               if (domain_runnable(inf->owner))
-                       extraq_add_tail(current);               //and add to the tail if it is runnable => round-robin
+               extraq_del(current);                                    //remove extradomain from head of the queue
+               
+               #if (EXTRA == EXTRA_ROUNDR)
+               if (domain_runnable(current))
+                       extraq_add_tail(current);                       //and add to the tail if it is runnable => round-robin
+               #elif (EXTRA == EXTRA_SLICE_WEIGHT)
+               oldscore   = inf->score;                                //update the score
+               inf->score = (inf->period << 10) / inf->slice;          //use fixed point arithmetic with 10 bits
+               
+               if (domain_runnable(current))
+                       extraq_add_sort_update(current, oldscore);      //add according to score: weighted round robin
+               #endif
                else
-                       __del_from_queue(inf->owner);           //if domain blocked in extratime remove it from waitq(/runq) as well
+                       __del_from_queue(inf->owner);                   //if domain blocked in extratime remove it from waitq(/runq) as well
        }
-       else {
+       else
+       #endif
+       {
                //current domain is running in real time mode
                //update the domains cputime
                inf->cputime += now - inf->sched_start;
@@ -315,13 +384,18 @@ static task_slice_t sedf_do_schedule(s_time_t now)
                        inf->cputime -= inf->slice;
                        
                        if (inf->period < inf->period_orig) {
-                               //this domain runs in latency scaling mode
-                               inf->period *= 2;
-                               inf->slice *= 2;
-                               if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) {
-                                       //now switch back to standard timing
-                                       inf->period = inf->period_orig;
-                                       inf->slice = inf->slice_orig;
+                               //this domain runs in latency scaling or burst mode
+                               #if (UNBLOCK == UNBLOCK_BURST)
+                               if (now - inf->absunblock >= 2 * inf->period)
+                               #endif
+                               {
+                                       inf->period *= 2;
+                                       inf->slice *= 2;
+                                       if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) {
+                                               //now switch back to standard timing
+                                               inf->period = inf->period_orig;
+                                               inf->slice = inf->slice_orig;
+                                       }
                                }
                        }
                        inf->absdead += inf->period;            //set next deadline
@@ -333,9 +407,11 @@ static task_slice_t sedf_do_schedule(s_time_t now)
                        __add_to_waitqueue_sort(inf->owner);
                else {
                        //we have a blocked realtime task
-                       inf->absblock=now;
+                       inf->absblock = now;
+                       #if (EXTRA > EXTRA_OFF)
                        if (inf->extra == EXTRA_AWARE)
                                extraq_del(inf->owner);         //remove a blocked domain from the extraq aswell
+                       #endif
                }
        }
 check_waitq:
@@ -393,13 +469,16 @@ check_waitq:
                if (!list_empty(waitq)) {
                        waitinf  = list_entry(waitq->next,struct sedf_dom_info,list);
                        //we could not find any suitable domain => look for domains that are aware of extratime
+                       #if (EXTRA > EXTRA_OFF)
                        if (!list_empty(extraq) && (PERIOD_BEGIN(waitinf) - now >= EXTRA_QUANTUM)) {
                                runinf   = list_entry(extraq->next,struct sedf_dom_info,extralist);
                                runinf->extra = EXTRA_RUNNING;
                                ret.task = runinf->owner;
                                ret.time = EXTRA_QUANTUM;
                        }
-                       else {
+                       else
+                       #endif
+                       {
                                //we have an empty run- and extraqueue or too less time => idle task!
                                ret.task = IDLETASK(cpu);
                                ret.time = PERIOD_BEGIN(waitinf) - now;
@@ -420,13 +499,19 @@ check_waitq:
 
 static void sedf_sleep(struct domain *d) {
        PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id);
-       if ( test_bit(DF_RUNNING, &d->flags) )
+       if ( test_bit(DF_RUNNING, &d->flags) ) {
+#ifdef ADV_SCHED_HISTO
+               adv_sched_hist_start(d->processor);
+#endif
                cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
+       }
        else  {
                if ( __task_on_queue(d) )
                        __del_from_queue(d);
+               #if (EXTRA > EXTRA_OFF)
                if (extraq_on(d))
                        extraq_del(d);
+               #endif
        }
 }
 
@@ -490,9 +575,8 @@ static void sedf_sleep(struct domain *d) {
  *      (or even worse: allocate a new full slice for the domain) 
  *     -either behaviour can lead to missed deadlines in other domains as opposed to approaches 1,2a,2b
  */
-static inline void unblock_short_vcons(struct sedf_dom_info* inf, s_time_t now) { inf->absdead += inf->period;}
-static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) {
-       inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period;         //very conservative
+static inline void unblock_short_vcons(struct sedf_dom_info* inf, s_time_t now) { 
+       inf->absdead += inf->period;
        inf->cputime = 0;
 }
 
@@ -500,19 +584,23 @@ static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) {
        inf->cputime += now - inf->absblock;                                            //treat blocked time as consumed by the domain
        if (inf->cputime + EXTRA_QUANTUM > inf->slice) {
                //we don't have a reasonable amount of time in our slice left :(
-               inf->cputime=0;
-               inf->absdead += inf->period;                                            //start in next period!
+               unblock_short_vcons(inf, now);                                          //start in next period!
        }
        else
-               inf->short_cont++;
+               inf->short_cont++;                                                      //we let the domain run in the current period
+}
+
+static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) {
+       inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period;         //very conservative
+       inf->cputime = 0;
 }
+
 static inline void unblock_long_cons_a(struct sedf_dom_info* inf, s_time_t now) {
        inf->cputime = (now - inf->absdead) % inf->period;                              //treat the time the domain was blocked in the CURRENT
                                                                                        //period as consumed by the domain
        if (inf->cputime + EXTRA_QUANTUM > inf->slice) {
                //we don't have a reasonable amount of time in our slice left :(
-               inf->cputime=0;
-               inf->absdead += inf->period;                                            //start in next period!
+               unblock_long_vcons(inf, now);                                           //start in next period!
        }
 }
 static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) {
@@ -521,20 +609,52 @@ static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) {
 }
 static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) {
        if (likely(inf->latency)) {
-               //sclae the slice and period accordingly to the latency hint
+               //scale the slice and period accordingly to the latency hint
                inf->period = inf->latency;                                             //reduce period temporarily to the latency hint
-               ASSERT((inf->latency < ULONG_MAX) && (inf->slice_orig < ULONG_MAX));    //this results in max. 4s slice/period length
-               inf->slice = (inf->latency * inf->slice_orig) / inf->period_orig;       //scale slice accordingly, so that utilisation stays the same
+               ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX));     //this results in max. 4s slice/period length
+               inf->slice = (inf->period * inf->slice_orig) / inf->period_orig;        //scale slice accordingly, so that utilisation stays the same
        }       
        else {
                //we don't have a latency hint.. use some other technique
-               inf->absdead = now + inf->period;                                       //Conservative 2b...
-               inf->cputime = 0;
+               unblock_long_cons_b(inf, now);
        }
 }
+//a new idea of dealing with short blocks: burst period scaling
+static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) {
+       inf->cputime += now - inf->absblock;                                            //treat blocked time as consumed by the domain
+       
+       if (inf->cputime + EXTRA_QUANTUM <= inf->slice) {
+               inf->short_cont++;                                                      //we let the domain run in the current period
+       }
+       else {
+               //we don't have a reasonable amount of time in our slice left => switch to burst mode
+               if (likely(inf->absunblock)) {
+                       inf->period = now - inf->absunblock;                            //set the period-length to the current blocking interval
+                       ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX));//this results in max. 4s slice/period length
+                       inf->slice = (inf->period * inf->slice_orig) / inf->period_orig;//scale slice accordingly, so that utilisation stays the same
+               }
+               else {
+                       inf->cputime=0;                                                 //in Case we haven't unblocked before
+                       inf->absdead += inf->period;                                    //start in next period!
+               }
+       }
+       inf->absunblock = now;
+}
+static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) {
+       if (unlikely(inf->latency && (inf->period > inf->latency))) {
+               //sclae the slice and period accordingly to the latency hint
+               inf->period = inf->latency;                                             //reduce period temporarily to the latency hint
+               ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX));     //this results in max. 4s slice/period length
+               inf->slice = (inf->period * inf->slice_orig) / inf->period_orig;        //scale slice accordingly, so that utilisation stays the same
+       }
+       else {
+               //we don't have a latency hint.. or we are currently in "burst mode": use some other technique
+               //this should be in fact the normal way of operation, when we are in sync with the device!
+               unblock_long_cons_b(inf, now);
+       }
+       inf->absunblock = now;
+}
 
-/*static inline void unblock_short_vcons
-static inline void unblock_short_vcons*/
 void sedf_wake(struct domain *d) {
        //for the first try just implement the "very conservative" way of waking domains up
        s_time_t              now = NOW();
@@ -555,16 +675,19 @@ void sedf_wake(struct domain *d) {
        if (unlikely(inf->absdead == 0))
                inf->absdead = now + inf->slice;                        //initial setup of the deadline
                
-       //very conservative way of unblocking
-       //make sure that the start of the period for this
-       //domain is happening in the future
        PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now);
        
        inf->block_tot++;
        if (unlikely(now< PERIOD_BEGIN(inf))) {
                //this might happen, imagine unblocking in extra-time!
                if (likely(inf->extra == EXTRA_AWARE)) 
+               #if (EXTRA == EXTRA_ROUNDR)
                        extraq_add_tail(d);                             //SD: Could extraq_add_head be better?
+               #elif (EXTRA == EXTRA_SLICE_WEIGHT)
+                       extraq_add_sort_update(d, 0);
+               #else
+                       ;
+               #endif
                //else
                //This is very very unlikely, ie. might even be an error?!
        }               
@@ -572,19 +695,48 @@ void sedf_wake(struct domain *d) {
                if (now < inf->absdead) {
                        //short blocking
                        inf->short_block_tot++;
-                       //unblock_short_vcons(inf, now);
+                       #if (UNBLOCK <= UNBLOCK_ATROPOS)
+                       unblock_short_vcons(inf, now);
+                       #elif (UNBLOCK == UNBLOCK_SHORT_RESUME)
                        unblock_short_cons(inf, now);
-                       if (inf->extra == EXTRA_AWARE) 
+                       #elif (UNBLOCK == UNBLOCK_BURST)
+                       unblock_short_burst(inf, now);
+                       #endif
+                       
+                       if (inf->extra == EXTRA_AWARE)
+                               #if (EXTRA == EXTRA_OFF)
+                               ;
+                               #elif (EXTRA == EXTRA_ROUNDR)
                                extraq_add_head(d);
+                               #elif (EXTRA == EXTRA_SLICE_WEIGHT)
+                               extraq_add_sort_update(d, 0);
+                               #endif
                }
                else {
                        //long blocking
                        inf->long_block_tot++;
                        //PRINT(3,"old=%llu ",inf->absdead);
-                       //unblock_long_vcons(inf, now);
-                       unblock_long_cons_c(inf,now);
+                       #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF)
+                       unblock_long_vcons(inf, now);
+                       #elif (UNBLOCK == UNBLOCK_EDF)
+                       unblock_long_cons_b(inf, now);
+                       #elif (UNBLOCK == UNBLOCK_ATROPOS)
+                       unblock_long_cons_c(inf, now);
+                       #elif (UNBLOCK == UNBLOCK_SHORT_RESUME)
+                       unblock_long_cons_b(inf, now);
+                       //unblock_short_cons_c(inf, now);
+                       #elif (UNBLOCK == UNBLOCK_BURST)
+                       unblock_long_burst(inf, now);
+                       #endif
+                       
                        if (inf->extra == EXTRA_AWARE) 
-                               extraq_add_tail(d);
+                               #if (EXTRA == EXTRA_OFF)
+                               ;
+                               #elif (EXTRA == EXTRA_ROUNDR)
+                               extraq_add_head(d);
+                               #elif (EXTRA == EXTRA_SLICE_WEIGHT)
+                               extraq_add_sort_update(d,0);
+                               #endif
                }
        }
        PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now);
@@ -592,7 +744,7 @@ void sedf_wake(struct domain *d) {
        PRINT(3,"added to waitq\n");    
        
        //do some statistics here...
-       if (inf->absblock!=0) {
+       if (inf->absblock != 0) {
                inf->block_time_tot += now - inf->absblock;
                inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock;
                /*if (DOM_INFO(d)->block_time_tot)
@@ -607,8 +759,12 @@ void sedf_wake(struct domain *d) {
        //and check, whether we are idling and this domain is extratime aware
        if ((PERIOD_BEGIN(inf) < schedule_data[d->processor].s_timer.expires) ||
            (is_idle_task(schedule_data[d->processor].curr) && (now + EXTRA_QUANTUM < schedule_data[d->processor].s_timer.expires) &&
-            (inf->extra == EXTRA_AWARE)))
+            (inf->extra == EXTRA_AWARE))) {
+#ifdef ADV_SCHED_HISTO
+               adv_sched_hist_start(d->processor);
+#endif
                cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
+       }
 }
 
 
@@ -616,9 +772,9 @@ void sedf_wake(struct domain *d) {
 static void sedf_dump_domain(struct domain *d) {
        printk("%u has=%c ", d->id,
                test_bit(DF_RUNNING, &d->flags) ? 'T':'F');
-       printk("p=%llu sl=%llu ddl=%llu w=%u c=%llu xtr(%s)=%llu",
+       printk("p=%llu sl=%llu ddl=%llu w=%u c=%llu sc=%i xtr(%s)=%llu",
                DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, DOM_INFO(d)->weight, d->cpu_time,
-               DOM_INFO(d)->extra ? "yes" : "no", DOM_INFO(d)->extra_time_tot);
+               DOM_INFO(d)->score, DOM_INFO(d)->extra ? "yes" : "no", DOM_INFO(d)->extra_time_tot);
        if (d->cpu_time !=0)
                printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) / d->cpu_time);
        if (DOM_INFO(d)->block_time_tot!=0)
index 86c39e1a9519c971a53b01004a059abe7889399e..3334c19ce0e7ba3ba9fd3bee3a7aea9146560a81 100644 (file)
@@ -34,6 +34,8 @@ string_param("sched", opt_sched);
 
 /*#define WAKE_HISTO*/
 /*#define BLOCKTIME_HISTO*/
+/*#define ADV_SCHED_HISTO*/
+//#include <xen/adv_sched_hist.h>
 
 #if defined(WAKE_HISTO)
 #define BUCKETS 31
@@ -198,6 +200,10 @@ void domain_wake(struct domain *d)
 /* Block the currently-executing domain until a pertinent event occurs. */
 long do_block(void)
 {
+#ifdef ADV_SCHED_HISTO
+    adv_sched_hist_start(current->processor);
+#endif
+
     ASSERT(current->id != IDLE_DOMAIN_ID);
     current->shared_info->vcpu_data[0].evtchn_upcall_mask = 0;
     set_bit(DF_BLOCKED, &current->flags);
@@ -209,6 +215,10 @@ long do_block(void)
 /* Voluntarily yield the processor for this allocation. */
 static long do_yield(void)
 {
+#ifdef ADV_SCHED_HISTO
+    adv_sched_hist_start(current->processor);
+#endif
+    
     TRACE_2D(TRC_SCHED_YIELD, current->id, current);
     __enter_scheduler();
     return 0;
@@ -328,8 +338,14 @@ void __enter_scheduler(void)
     perfc_incrc(sched_run);
     
     spin_lock_irq(&schedule_data[cpu].schedule_lock);
+
+#ifdef ADV_SCHED_HISTO
+    adv_sched_hist_from_stop(cpu);
+#endif
     now = NOW();
+#ifdef ADV_SCHED_HISTO
+    adv_sched_hist_start(cpu);
+#endif
 
     rem_ac_timer(&schedule_data[cpu].s_timer);
     
@@ -369,9 +385,12 @@ void __enter_scheduler(void)
     if ( !is_idle_task(next) )
         update_dom_time(next->shared_info);
 
-    if ( unlikely(prev == next) )
+    if ( unlikely(prev == next) ) {
+#ifdef ADV_SCHED_HISTO
+        adv_sched_hist_to_stop(cpu);
+#endif
         return;
-    
+    }
     perfc_incrc(sched_ctx);
 
 #if defined(WAKE_HISTO)
@@ -393,7 +412,6 @@ void __enter_scheduler(void)
 #endif
 
     TRACE_2D(TRC_SCHED_SWITCH, next->id, next);
-
     switch_to(prev, next);
 
     /*
@@ -407,7 +425,10 @@ void __enter_scheduler(void)
     /* Mark a timer event for the newly-scheduled domain. */
     if ( !is_idle_task(next) )
         send_guest_virq(next, VIRQ_TIMER);
-    
+
+#ifdef ADV_SCHED_HISTO
+    adv_sched_hist_to_stop(cpu);
+#endif
     schedule_tail(next);
 
     BUG();
@@ -431,6 +452,10 @@ int idle_cpu(int cpu)
 /* The scheduler timer: force a run through the scheduler*/
 static void s_timer_fn(unsigned long unused)
 {
+#ifdef ADV_SCHED_HISTO
+    adv_sched_hist_start(current->processor);
+#endif
+
     TRACE_0D(TRC_SCHED_S_TIMER_FN);
     raise_softirq(SCHEDULE_SOFTIRQ);
     perfc_incrc(sched_irq);
@@ -572,6 +597,63 @@ void reset_sched_histo(unsigned char key)
             schedule_data[j].hist[i] = 0;
 }
 #else
+#if defined(ADV_SCHED_HISTO)
+void print_sched_histo(unsigned char key)
+{
+    int i, j, k,t;
+    printf("Hello!\n");
+    for ( k = 0; k < smp_num_cpus; k++ )
+    {
+        j = 0;
+       t = 0;
+        printf ("CPU[%02d]: scheduler latency histogram FROM (ms:[count])\n", k);
+        for ( i = 0; i < BUCKETS; i++ )
+        {
+            //if ( schedule_data[k].hist[i] != 0 )
+            {
+               t += schedule_data[k].from_hist[i];
+                if ( i < BUCKETS-1 )
+                    printk("%3d:[%7u]    ", i, schedule_data[k].from_hist[i]);
+                else
+                    printk(" >:[%7u]    ", schedule_data[k].from_hist[i]);
+                //if ( !(++j % 5) )
+                    printk("\n");
+            }
+        }
+        printk("\nTotal: %i\n",t);
+    }
+    for ( k = 0; k < smp_num_cpus; k++ )
+    {
+        j = 0; t = 0;
+        printf ("CPU[%02d]: scheduler latency histogram TO (ms:[count])\n", k);
+        for ( i = 0; i < BUCKETS; i++ )
+        {
+            //if ( schedule_data[k].hist[i] != 0 )
+            {
+               t += schedule_data[k].from_hist[i];
+                if ( i < BUCKETS-1 )
+                    printk("%3d:[%7u]    ", i, schedule_data[k].to_hist[i]);
+                else
+                    printk(" >:[%7u]    ", schedule_data[k].to_hist[i]);
+                //if ( !(++j % 5) )
+                    printk("\n");
+            }
+        }
+       printk("\nTotal: %i\n",t);
+    }
+      
+}
+void reset_sched_histo(unsigned char key)
+{
+    int i, j;
+    for ( j = 0; j < smp_num_cpus; j++ ) {
+        for ( i=0; i < BUCKETS; i++ ) 
+            schedule_data[j].to_hist[i] = schedule_data[j].from_hist[i] = 0;
+        schedule_data[j].save_tsc = 0;
+    }
+}
+#else
 void print_sched_histo(unsigned char key) { }
 void reset_sched_histo(unsigned char key) { }
 #endif
+#endif
index 15f992614ae80c1f18c8bc05e3e9da5c725f458e..a33b0559ed11c5183a745613576a8e45d11b7e06 100644 (file)
@@ -7,7 +7,9 @@
  * Portions by Mark Williamson are (C) 2004 Intel Research Cambridge
  */
 
-#define BUCKETS 10
+//#define ADV_SCHED_HISTO
+#define BUCKETS  10
+/*300*/
 
 typedef struct schedule_data_st
 {
@@ -17,6 +19,11 @@ typedef struct schedule_data_st
     struct domain       *idle;          /* idle task for this cpu */
     void *              sched_priv;
     struct ac_timer     s_timer;        /* scheduling timer  */
+#ifdef ADV_SCHED_HISTO
+    u32                        to_hist[BUCKETS];
+    u32                        from_hist[BUCKETS];
+    u64                        save_tsc;
+#endif
 #ifdef BUCKETS
     u32                 hist[BUCKETS];  /* for scheduler latency histogram */
 #endif
@@ -55,5 +62,3 @@ struct scheduler
 
 /* per CPU scheduler information */
 extern schedule_data_t schedule_data[];
-
-